﻿using StarPizza;
using StarPizza.Model.BaseModel;
using StarPizza.Model.Ordering;
using StarPizza.ViewModel.Core;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace StarPizza.ViewModel.ManagerSystem
{
    public enum ReportKind
    {
        ListByPizzaTemplate,
        RatioByPizzaTemplate,
        RatioByDistrict
    }
    class ReportCreator : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged(string propertyName)
        {
            if (this.PropertyChanged != null)
            {
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        OrderHistory orderHistory;
        PizzaTemplateLister pizzaTemplateLister;
        
        public PizzaTemplateLister PizzaTemplateLister { get { return pizzaTemplateLister; } }
        private bool contextChanged;
        public bool ContextChanged
        {
            get { return contextChanged; }
            set
            {
                if (value != contextChanged)
                {
                    contextChanged = value;
                    OnPropertyChanged("ContextChanged");
                }
            }
        }

        private ReportKind reportKind;
        public ReportKind ReportKind
        {
            get { return reportKind; }
            set
            {
                if (value != reportKind)
                {
                    reportKind = value;
                    ContextChanged = true;
                    OnPropertyChanged("ReportKind");
                }
            }
        }

        private DateTime startDate;
        public DateTime StartDate
        {
            get { return startDate; }
            set
            {
                if (value != startDate)
                {
                    startDate = value;
                    EnsureConsistentDateRange();
                    ContextChanged = true;
                    OnPropertyChanged("StartDate");
                }
            }
        }

        private DateTime endDate;
        public DateTime EndDate
        {
            get { return endDate; }
            set
            {
                if (value != endDate)
                {
                    endDate = value;
                    EnsureConsistentDateRange();
                    ContextChanged = true;
                    OnPropertyChanged("EndDate");
                }
            }
        }
        
        private void EnsureConsistentDateRange()
        {
            if (StartDate > EndDate)
            {
                StartDate = EndDate;
            }
        }

        public ObservableCollection<OrderedPizzaReportVM> SelectedOrdersByTemplate
        {
            get;
            private set;
        }

        private Dictionary<string, int> countPerGroup;
        public Dictionary<string, int> CountPerGroup
        {
            get { return countPerGroup; }
            set
            {
                if (value != countPerGroup)
                {
                    countPerGroup = value;
                    OnPropertyChanged("CountPerGroup");
                }
            }
        }
        public ReportCreator(OrderHistory orderHistory, PizzaTemplateLister pizzaTemplateLister)
        {
            this.orderHistory = orderHistory;
            this.pizzaTemplateLister = pizzaTemplateLister;

            var oneYear = new TimeSpan(days: 365, hours: 0, minutes: 0, seconds: 0);
            startDate = DateTime.Now.Subtract(oneYear);
            endDate = DateTime.Now;
            reportKind = ReportKind.ListByPizzaTemplate;
            pizzaTemplateLister.PizzaTemplateVMSelected += pizzaTemplateLister_PizzaTemplateVMSelected;

            CountPerGroup = new Dictionary<string, int>();
            SelectedOrdersByTemplate = new ObservableCollection<OrderedPizzaReportVM>();
            ContextChanged = true;
        }

        void pizzaTemplateLister_PizzaTemplateVMSelected(PizzaTemplateVM pizzaTemplateVM)
        {
            ContextChanged = true;
        }
        private Dictionary<TKey, int> GroupingToCountDictionary<TKey>(IQueryable<IGrouping<TKey,OrderedPizzaInfo>> grouping)
        {
            return grouping.ToDictionary(
                group => group.Key, 
                group => group.Count());
        }
        public void RegenerateReport()
        {
            var unfilteredPizzaInfo = orderHistory.GetOrderedPizzasBetween(StartDate, EndDate);
            switch (ReportKind)
            {
                case ReportKind.ListByPizzaTemplate:
                    var specificPizzaInfo = unfilteredPizzaInfo
                        .Where(pizzaInfo => pizzaInfo.PizzaTemplate == pizzaTemplateLister.SelectedPizzaTemplateVM.WrappedPizzaTemplate);
                    SelectedOrdersByTemplate.Clear();
                    SelectedOrdersByTemplate.AddItems( 
                        specificPizzaInfo.ToList()
                        .ConvertAll(pizzaInfo => new OrderedPizzaReportVM(pizzaInfo)));
                    break;
                case ReportKind.RatioByPizzaTemplate:
                    var templateGrouping = unfilteredPizzaInfo.GroupBy(pizzaInfo => pizzaInfo.PizzaTemplate);
                    Dictionary<PizzaTemplate, int> pizzaCountPerTemplate = GroupingToCountDictionary(templateGrouping);
                    CountPerGroup = pizzaCountPerTemplate.ToDictionary(kpv => kpv.Key.Name, kpv => kpv.Value);
                    break;
                case ReportKind.RatioByDistrict:
                    var districtGrouping = unfilteredPizzaInfo.GroupBy(pizzaInfo => pizzaInfo.OrderInfo.Client.District);
                    Dictionary<int, int> pizzaCountPerDistrict = GroupingToCountDictionary(districtGrouping);
                    CountPerGroup = pizzaCountPerDistrict.ToDictionary(kpv => kpv.Key.ToString(), kpv => kpv.Value);
                    break;
                default:
                    break;
            }
            ContextChanged = false;
        }
    }
}
